<?php
namespace PsiFramework\Classes\Util;

import("Classes.Util.Parameters.ObjectParameters");
import("Classes.Util.Parameters.Action.ActionMapping");
import("Classes.Util.Log.Logger");

use \PsiFramework\Classes\Util\Parameters\Parameters;
use \PsiFramework\Classes\Util\Parameters\ObjectParameters;
use \PsiFramework\Classes\Util\Parameters\Action\ActionMapping;
use \PsiFramework\Classes\Util\Parameters\DAO\ObjectParametersDAO;
use \PsiFramework\Classes\Util\Log\Logger;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */

/**
 * The Plugin class describes a Plugin
 *
 * @package Model
 */
class Plugin
{

    protected /*string*/             $_name ;
    protected /*Plugin*/             $_parent ;
    protected /*Plugin[]*/           $_dependencies;
    protected /*ActionMapping*/      $_actionMapping;
    protected /*array*/              $_serviceMapping;
    protected /*ObjectParameters[]*/ $_objectParameters;
    protected /*Parameters*/         $_parameters;
    
    protected /*bool*/               $_objectParametersRetrieved;

    protected /*Logger*/             $_logger;

    /**
     *
     * @param string $name
     * @param Plugin $parent
     * @param Plugin[] $dependencies
     * @param ActionMapping $actionMapping
     * @param array $serviceMapping
     * @param ObjectParameters[] $objectParameters
     * @param Parameters $parameters
     */
    public function __construct(
        /*string*/             $name=null,
        Plugin                 $parent=null,
        /*Plugin[]*/           $dependencies=null,
        ActionMapping          $actionMapping=null,
        /*array*/              $serviceMapping=null,
        /*ObjectParameters[]*/ $objectParameters=null,
        /*Parameters*/         $parameters=null
    )
    {
        $this->_name = $name ;
        $this->_parent = $parent ;
        $this->_dependencies = $dependencies ;
        $this->_actionMapping = $actionMapping ;
        $this->_serviceMapping = $serviceMapping ;
        $this->_objectParameters = $objectParameters ;
        $this->_parameters = $parameters ;

        $this->_objectParametersRetrieved = false;
        
        $this->_logger = new Logger("Plugin");
    }

    public function addObjectParameter(ObjectParameters $objectParameter)
    {
        $this->_logger->debug(
            "Adding '".$objectParameter->getName().
            "' to plugin '".$this->_name."'"
        );
        $this->_objectParameters[
            $objectParameter->getName()
        ] = $objectParameter ;
        ObjectParametersDAO::$objectParameters[
            $objectParameter->getName()
        ] = $objectParameter ;
    }

    public function getName()
    {
        return $this->_name ;
    }

    public function getParent()
    {
        return $this->_parent ;
    }

    public function getDependencies()
    {
        return $this->_dependencies ;
    }

    public function getActionMapping()
    {
        return $this->_actionMapping ;
    }

    public function getServiceMapping()
    {
        return $this->_serviceMapping ;
    }

    public function getObjectParameters()
    {
        return $this->_objectParameters ;
    }

    public function getParameters()
    {
        return $this->_parameters ;
    }

    public function setName($name)
    {
        return $this->_name = $name ;
    }

    public function setParent(Plugin $parent=null)
    {
        return $this->_parent = $parent ;
    }

    public function setDependencies(/*array*/ $dependencies)
    {
        return $this->_dependencies = $dependencies ;
    }

    public function setActionMapping(ActionMapping $actionMapping=null)
    {
        return $this->_actionMapping = $actionMapping ;
    }

    public function setServiceMapping(/*array*/ $serviceMapping)
    {
        return $this->_serviceMapping = $serviceMapping ;
    }

    public function setObjectParameters(/*array*/ $objectParameters)
    {
        return $this->_objectParameters = $objectParameters ;
    }

    public function setParameters(Parameters $parameters=null)
    {
        return $this->_parameters = $parameters ;
    }

    public function getAction(/*string*/ $actionName=null)
    {
        if (isNullOrEmptyString($actionName)) {
            $actionName = $this->_defaultAction ;
        }

        $action = null ;
        if (!is_null($this->_actionMapping)) {
            $action = $this->_actionMapping->getAction($actionName);
        }


        if (is_null($action) && !is_null($this->_parent)) {
            $action = $this->_parent->getAction($actionName);
        }

        if (is_null($action) && !is_null($this->_dependencies)) {
            foreach ($this->_dependencies as $dependency) {
                $action = $dependency->getAction($actionName);
                if (!is_null($action)) {
                    break ;
                }
            }
        }

        return $action ;
    }

    public function getServiceClass(/*string*/ $serviceName)
    {
        $serviceClass =null ;

        if (!is_null($this->_serviceMapping)
            && array_key_exists($serviceName, $this->_serviceMapping)
        ) {
            $serviceClass = $this->_serviceMapping[$serviceName] ;
        }

        if (is_null($serviceClass) && !is_null($this->_parent)) {
            $serviceClass = $this->_parent->getServiceClass($serviceName);
        }

        if (is_null($serviceClass) && !is_null($this->_dependencies)) {
            foreach ($this->_dependencies as $dependency) {
                $serviceClass = $dependency->getServiceClass($serviceName);
                if (!is_null($serviceClass)) {
                    break ;
                }
            }
        }

        return $serviceClass ;
    }

    public function getObjectParameter(/*string*/ $objectName)
    {
        if (isNullOrEmptyString($objectName)) {
            throw new \Exception(
                "Can't retrieve an object with a null name !"
            ); ;
        }

        $objectParameter = null ;

        $this->_logger->debug(
            "Retrieving '".$objectName."' from plugin '".$this->_name."'"
        );

        if (!is_null($this->_objectParameters)
            && isset($this->_objectParameters[$objectName])
        ) {
            $objectParameter = $this->_objectParameters[$objectName] ;
        }
        if (is_null($objectParameter) && !is_null($this->_parent)) {
            try{
                $objectParameter = $this->_parent->getObjectParameter(
                    $objectName
                );
            }catch(\Exception $e) {
                $objectParameter = null ;
            }
        }
        if (is_null($objectParameter) && !is_null($this->_dependencies)) {
            foreach ($this->_dependencies as $dependency) {
                try{
                    $objectParameter = $dependency->getObjectParameter(
                        $objectName
                    );
                }catch(\Exception $e) {
                    $objectParameter = null ;
                }
                if (!is_null($objectParameter)) {
                    break ;
                }
            }
        }

        if (is_null($objectParameter)) {
            throw new \Exception(
                "The object '".$objectName."' couldn't be retrieved for Plugin '".$this->getName()."' !"
            );
        }

        return $objectParameter ;
    }
    
    public function isObjectParametersRetrieved() {
        return $this->_objectParametersRetrieved;
    }
    
    public function setObjectParametersRetrieved($objectParametersRetrieved) {
        $this->_objectParametersRetrieved = $objectParametersRetrieved;
    }

    public function getParameter(/*string*/ $paramName)
    {
        if (isNullOrEmptyString($paramName)) {
            return null ;
        }

        $param = null ;
        if (!is_null($this->_parameters)) {
            $param = $this->_parameters->getParameter($paramName);
        }

        if (is_null($param) && !is_null($this->_parent)) {
            $param = $this->_parent->getParameter($paramName);
        }
        if (is_null($param) && !is_null($this->_dependencies)) {
            foreach ($this->_dependencies as $dependency) {
                $param = $dependency->getParameter($paramName);
                if (!is_null($param)) {
                    break ;
                }
            }
        }
        return $param ;
    }
}
